20180615 JaSST'18 Kansai 参加メモ
基調講演 1000-1130 和田卓人さん 『テスト駆動開発から品質保証へと橋を架ける』
どうやって橋をかけるかという話をする
大部分はライブコーディング 8割くらいはライブコーディング
資料公開あり 撮影OK 実況も歓迎
自己紹介
てぃーわださんと呼ばれています
書籍の監訳翻訳などされています
最近の立ち位置
LTの最後に貼ったコラージュが拡散されてしまった
テストコードを書かない、は、コードがリジェクトされる大きな理由になってきている
一種の恫喝の道具としていいように使われている(笑)
なまはげのような存在 「テスト書いてないとてぃーわだがくるぞ」
本人はジェントルな人格
海外では
非英語圏で主に支持されている
power-assertの開発
アリババさんが主に使われている
よろしくお願いします
今日はテスト駆動開発について、実際に見せる
百聞は一見にしかず
Q&A
TDD はまだよくわからないです
具体的な方法がわかりません
テスト駆動開発とは何か
みなさんがこれから目撃するもの
実際にやってみせるまでのスキルの階段がある
書籍
ダイレクトマーケティング
これがいちばんのおすすめです 著者がケントベックだから
自習に最適な本になっている
TDDのサイクル
ざっくり要約すると
サイクルである
Red Green Refactoring のサイクルを繰り返す
入る前に、小さい設計のプロセスを踏む
よくある誤解 テスト設計をせずにコードを書く
ただ、近いものから詳細にやる、という点は特徴的
ジャストインタイムの設計
近い場合は「詳細に」遠い場合は「置いておく」 プル型
箇条書きされたToDoリストのようなものがテスト設計になるイメージ
これも作り込み過ぎない
必要なときに必要なだけ1個流す
最初にテストを全部書くのは、テストファーストであるがテスト駆動開発ではない
いちばん欲しいもの もしくは いちばんちょろいやつ から倒していく おすすめは後者
できあがったらどうなってほしいと思う? 自分はこう動いてほしい こういうコードが欲しい
最短距離で成功させるコードを書く とにかく動かすことに集中する コピペでもなんでもいい グリーン
呪いの言葉 「うごくコードに触れるな」 うごいていないソフトウェアは価値を提供できないから
ずっと、このソフトウェアの業界を蝕んでいた
技術で解決できる時代になった
バージョン管理
CI
自動テスト
一般的なリファクタリング 外部からみたふるまいが変わらないまま、内部を綺麗にする
TDDのリファクタリング 成功しているテストが成功しているままで、コードを綺麗にする もうちょっと定義が細かい
このサイクルを何万回もぐるぐる回す
リファクタリングの終了条件は様々 デモで説明される
デモ FizzBuzz問題
実は毎回アレンジしている
ある面接の記事で有名になった (ちょっと昔はナベアツで通じた)
ライブコーディング
言語 真ん中をとってJavaで
ToDoリスト 紙でもホワイトボードでもよい
たかがFizzBuzzのくせに、一撃で撃破するには実は大きい ひとくちサイズではない
1から100
むずかしくはないが面倒である要素
妙に数が多い プログラマの怠惰さを喚起する面倒臭さがある
コアロジックが先に欲しい
プリントする
Javaでいうとやや難しい
技術的な難易度は高いのに、あまり報われない 価値がない 投資対効果が低い
そういうのは下にもってきたい
<いまのTODOリスト> ※抜粋
- [ ] 1から100までの数
- [ ] プリントする
「ただし、」という言葉
黄色く見える
なんらかのオルタナティブなフローを示している
後ろにあるもの
形式が揃っていない
形式を揃える
<いまのTODOリスト> ※抜粋
ただし、
3の倍数〜
5の倍数〜
3と5両方の倍数〜
- [ ] 1から100までの数
- [ ] プリントする
ボトムアッププログラミングの様子
ただし、が一番上にあるのはおかしい
前にあったものを後ろにまわしたけど、隠れていたものはなに?
数をプリントする → 数を変換する → 数を文字列に変換する
このコアロジックを危うく見落とすところだった
詳細設計かというとちょっと違う
テスト対象を分解する が一番最初のプロセス
1週目は簡単な相手を倒す
数を文字列に変換する がいちばん簡単
JUnitのテストケースをつくる
パッケージとか名前空間を決める
テストクラスの名前を考えることは大きな仕事
ここで、この問題に最初に直面する
じゃあFizzBuzzTestにしよう
最近は「Test」を後ろにつけることが主流になってきている
他対他をひとつのファイルにおさめることが可能になってきた
おおむね一対一であるならば、後ろにあるのがシンプルなんじゃないかという考え
おもむろに失敗する
エラーが出る
"これは失敗するはず" と書くプロセスが大事
スタート地点に立つことが大事
RedバーがまさにFailメソッドによって出ていることを確認する
この「助走」がすごくすごく大事
自分の予想通りテストが失敗するということは、状況をコントロールできているということ、だから嬉しい
テストコードに戻る
@Testを追加する
名前が大事
「void 数を文字列に変換する()」
お前は何を言ってるんだ → テストコードは動作するドキュメントなので、日本語で開発するのであれば、日本語としてわかりやすいことが大事
主な構成 3A
前準備 アレンジ
実行 アクター
検証 アサート
テスト駆動開発では、これを下から書く
JUnitでは、assertEquals(expected, actual)
下から書くことで、ゴールをブレさせないようにできる
何がゴールか? 数を文字列に変換できればよい
ここで手が止まる 具体的な数で考えなければいけないから
テストコードは徹頭徹尾、具体的にしか書けない
残酷だが大事な瞬間
具体的に考えることで、像がシャープになる
1を渡すと文字列1に変換する()」
型はString
まだプロダクションコードは存在しない
作る前に使う側にまわる
作ってしまうと、なんとか使ってほしいというバイアスがかかる
作りやすいものと使いやすいものは両立しにくい
使いやすいものの方が価値が高い
コンパイルエラーを逆手にとって、プロダクトコードを書く
コンパイルエラーの森を抜ける
テストは引き続き失敗する
さっきまではコンパイルエラーだった
こんどは、1を渡すとnullが返ってエラーになった
ここで、サイクルの3番まできた
これだけ大変だから、最初に倒すのは簡単なやつを選ぶ
火が入ったので、エンジンを駆動していく
return "1"
茶番だが、1週目だけは茶番ではない
ここでGreenになった
これでもし失敗したら、失敗はテストコード側にあるとわかる
15年前の質問 「テストコードにバグがあったらどうするの君!」
意図的に誤りを入れる
理論上は可能だが、時間がかかる
エフェクティブでもプラクティカルでもない
じゃあ、テストのコストがいちばん低いタイミングでやっちゃおう
このタイミングでテストを仕留めてしまう
いま我々はオールグリーン
リファクタリングの権利または義務がある
リファクタリング
実行と検証をまとめる
ToDoリストを更新する
<いまのTODOリスト> ※抜粋
x 数を文字列に変換する
x1を渡すと〜 > 仮実装
x 2を渡すと〜 >三角測量
ただし、
3の倍数〜
5の倍数〜
3と5両方の倍数〜
- 1から100までの数
- プリントする
実務では、アサーションを縦に並べるのはアンチパターン
どこが悪いのかを調べないといけなくなる
テストごとに、アサーションがひとつしかない状態にする
テストを分けて、状況としては前進
スリーアウトまで待つ
スリーアウトになった
でもいきなりリファクタリングにはいけない
なぜならグリーンじゃないから
いくつかやり方があるが、今回はすべてを強引に緑にする
これでリファクタリングをする権利を手に入れた
リファクタリング
オールグリーンのまま安全に移動する
段階を踏む
次は5の倍数
予想通り失敗する
実装に恐れはない
仮実装も要らなくなる
予想通り成功する
もっともコンディションの良い状態 → 明白な実装
TDDのスキル
問題を小さくすることで、エンジンに火を入れる
歩幅を調整する ギアを変える
最初は不安だらけだったので、仮実装して三角測量して実装する
次は、三角測量が不要になったので、仮実装して実装する
最後に、実装にも不安がなくなったので、最初から明白な実装をする
Q&A
開発者がテストを書くようになったら〜
TDDのTについて考える
動作する綺麗なコード
分割統治
エラーをみつけるつもりでプログラムを実行する過程
TDDはこれではない
ソフトウェアテストのやり方ではない
強い意思をもって動作する綺麗なコードを書くための、プログラミングテクニック
テスティングフレームワークを使った、コーディング
Testing vs. Checking
「CDD」にはならなかった
詳しくは付録Cを参照
アジャイルテストの四象限
この図としては、「アジャイル」は特に関係ない
これでいうと、TDDは一部はカバーしているが、全部をカバーする気はない
人間が人間にしかできない創造性を発揮する領域は残る
TDDにおける考え方
実質はプログラミングテクニックである
インパクトは強かったので、世の中を大きく変えた
ユニットテストの自動化、受け入れテストの自動化に大きく貢献
Q&A
維持コストなど
テストの構造化とリファクタリング
山を越えると約束の地が待っていて。。。
と思ったら、前任者の残したものをとにかく直すことに時間をとられる現実が待っていた
テストを書いた人とメンテナンスする人が異なる
実は、デモのFizzBuzzは完全ではなかった
あれ?具体的なふるまいは書かれているけど、仕様がわからない! (忖度はできる)
前任者の書き散らかした、意図のわからないテストコードが大量に残っている
実はこれは「悪い例」
どうするべきだったのか
仕様レベルのことばを、復元しておいて欲しかった
エンジンに火を入れるために、具体例に踏み込んだ結果、具体例しか残らなくなった
対応例:メソッド名をやたらと長くする(メソッド名に意図を含めてしまう)
仕様の階層と、具体例の階層をつくる(ToDoリストのツリー構造をコードに持ち込む)
2にあまり意味はない
最初にサイクルの歩幅を小さくした結果 単なる書き順の話
意味ありげに残っているけど、大して意味がないテストがある
対応例:2のテストコードは消しておく
書き終わったら整理する
プログラマの自身と不安に寄り添って、前に進む力を与える
境界値ってどこなの?
こういう話は、プログラマは気付きにくい
「例えば境界値を意識してみたら?」
そういった形で協業していける
実装を前に進める値 もう一つ値を追加するとしたら?
ペアプロ中に、どんな値を選ぶかを助言する
プログラマは、テストを減らすことは苦手
このときの作者の気持ちを答えよ
ではない
書くだけがテストではない
きちんと書いて、並べて、整理する
テストはプロの嗜み
(質問タイム)レガシーコードとどう戦うか
「レガシーコード改善ガイド」
ジレンマをかかえている 後からテストを書きにくい
コードを安全に変更するにはテストを書きたい デッドロック
外から無理やりテストを書くか WEB系はこちらを採用することが多い
安全に慎重にコードを変えるか 組み込み系はこちらを採用することが多い